#include "attribute_info.h"
#include "util.h"
#include <iostream>
#include <string>
using namespace std;

attribute_info* attribute_info::create(char* &buffer,vector<cp_info*> constant_pool) {
	short index;
	int length;
	index = getU2(buffer);buffer += 2;
	length = getU4(buffer);buffer += 4;
	//cout<<"index::"<<index<<'\n';
	//cout<<"length::"<<length<<'\n';
	//wstring attribute_name = ((constant_utf8_info*)constant_pool[index])->bytes;
	//wcout<<"attribute_name::"<<attribute_name<<endl;
	attribute_info *info = NULL;
	if(attribute_name == L"ConstantValue"){
		info = new constant_value_attribute();
		((constant_value_attribute*)info)->constantvalue_index = getU2(buffer);buffer += 2;
	}else if(attribute_name == L"Code"){
		info = new code_attribute();
		((code_attribute*)info)->max_stack = getU2(buffer);buffer += 2;
		((code_attribute*)info)->max_locals = getU2(buffer);buffer += 2;
		((code_attribute*)info)->code_length = getU4(buffer);buffer += 4;
		for(int i = 0; i < ((code_attribute*)info)->code_length; i++) {
			((code_attribute*)info)->code.push_back(getU1(buffer));buffer++;
		}
		((code_attribute*)info)->exception_table_length = getU2(buffer);buffer += 2;
		for(int i = 0; i < ((code_attribute*)info)->exception_table_length; i++){
			code_attribute::exception_table_c *et = new code_attribute::exception_table_c();
			et->start_pc = getU2(buffer);buffer += 2;
			et->end_pc = getU2(buffer);buffer += 2;
			et->handler_pc = getU2(buffer);buffer += 2;
			et->catch_type = getU2(buffer);buffer += 2;
			((code_attribute*)info)->exception_table.push_back(et);
		}
		((code_attribute*)info)->attributes_count = getU2(buffer);buffer += 2;
		for(int i = 0; i < ((code_attribute*)info)->attributes_count; i++){
			attribute_info::create(buffer, constant_pool);
		}
	}else if(attribute_name == L"Exceptions") {
		info = new exceptions_attribute();
		((exceptions_attribute*)info)->number_of_exceptions = getU2(buffer);buffer += 2;
		for(int i = 0; i < ((exceptions_attribute*)info)->number_of_exceptions; i++){
			((exceptions_attribute*)info)->exception_index_table.push_back(getU2(buffer));buffer += 2;
		}
	}else if(attribute_name == L"InnerClasses"){
		info = new inner_classes_attriubte();
		((inner_classes_attriubte*)info)->number_of_classes = getU2(buffer);buffer += 2;
		for(int i = 0; i < ((inner_classes_attriubte*)info)->number_of_classes; i++){
			inner_classes_attriubte::classes_c *c = new inner_classes_attriubte::classes_c();
			c->inner_class_info_index = getU2(buffer);buffer += 2;
			c->outer_class_info_index = getU2(buffer);buffer += 2;
			c->inner_name_index = getU2(buffer);buffer += 2;
			c->inner_class_access_flags = getU2(buffer);buffer += 2;
			((inner_classes_attriubte*)info)->classes.push_back(c);
		}
	}else if(attribute_name == L"Synthetic"){
		info = new synthetic_attribute();
	}else if(attribute_name == L"SourceFile"){
		info = new sourcefile_attribute();
		((sourcefile_attribute*)info)->sourcefile_index = getU2(buffer);buffer += 2;
		cout<<"SourceFile::"<<((sourcefile_attribute*)info)->sourcefile_index<<endl;
	}else if(attribute_name == L"LineNumberTable"){
		info = new line_number_table_attribute();
		((line_number_table_attribute*)info)->line_number_table_length = getU2(buffer);buffer += 2;
		for(int i = 0; i < ((line_number_table_attribute*)info)->line_number_table_length; i++){
			line_number_table_attribute::line_number_table_c *lnt = new line_number_table_attribute::line_number_table_c();
			lnt->start_pc = getU2(buffer);buffer += 2;
			lnt->line_number = getU2(buffer);buffer += 2;
			((line_number_table_attribute*)info)->line_number_table.push_back(lnt);
		}
	}else if(attribute_name == L"LocalVariableTable"){
		info = new local_variable_table_attribute();
		((local_variable_table_attribute*)info)->local_variable_table_length = getU2(buffer);buffer += 2;
		for(int i = 0; i < ((local_variable_table_attribute*)info)->local_variable_table_length; i++){
			local_variable_table_attribute::local_variable_table_c *c = new local_variable_table_attribute::local_variable_table_c();
			c->start_pc = getU2(buffer);buffer += 2;
			c->length = getU2(buffer);buffer += 2;
			c->name_index = getU2(buffer);buffer += 2;
			c->descriptor_index = getU2(buffer);buffer += 2;
			c->index = getU2(buffer);buffer += 2;
			((local_variable_table_attribute*)info)->local_variable_table.push_back(c);
		}
	}else if(attribute_name == L"Deprecated"){
		info = new deprecated_attribute();
	}else {
		buffer += length;
		return NULL;
	}
	info->attribute_length = length;
	info->attribute_name_index = index;
	return info;
}